﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Tomahawk.Resources.Materials;
using System.IO;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Tomahawk.Runtime.Rendering.Materials;
using Tomahawk.Resources.Particles;
using Microsoft.Xna.Framework;

namespace Tomahawk.Runtime.Rendering.Particles
{
    public class ParticlesManager
    {
        #region Properties
        protected class EffectsTable : Dictionary<string, SASEffect>
        {
            public EffectsTable() : base(StringComparer.OrdinalIgnoreCase) { }
        };
        protected Dictionary<ParticleSettingsCollection, EffectsTable> collections = new Dictionary<ParticleSettingsCollection, EffectsTable>();
        #endregion

        #region Initialization
        public ParticlesManager()
        {
            ParticleSettingsCollectionReader.OnInitParticleSettingsCollection += new ParticleSettingsCollectionReader.InitParticleSettingsCollectionDelegate(OnInitParticleSettingsCollection);
        }

        public bool OnInitParticleSettingsCollection(ParticleSettingsCollection collection)
        {
            collection.OnDispose += new ParticleSettingsCollection.OnDisposedDelegate(collection_OnDispose);
            return true;
        }

        void collection_OnDispose(ParticleSettingsCollection collection)
        {
            collections.Remove(collection);
        }
        #endregion

        public void Clear()
        {
            collections.Clear();
        }

        #region Loading
        protected SASEffect Build(ParticleSettings settings, ContentManager contentManager)
        {
            SASEffect sasEffect = new SASEffect();
            sasEffect.Initialize(SASParticles.EffectFile, contentManager);

            SASEffect.SASEffectParametersCollection parameters = sasEffect.Parameters;

            Vector4 gravity = new Vector4(settings.Gravity, 0.0f);
            Vector4 minColor = settings.MinColor.ToVector4();
            Vector4 maxColor = settings.MaxColor.ToVector4();
            Vector4 rotateSpeed = new Vector4(settings.MinRotateSpeed, settings.MaxRotateSpeed, 0.0f, 0.0f);
            Vector4 startSize = new Vector4(settings.MinStartSize, settings.MaxStartSize, 0.0f, 0.0f);
            Vector4 endSize = new Vector4(settings.MinEndSize, settings.MaxEndSize, 0.0f, 0.0f);

            parameters["Duration"].SetFloatValue(ref settings.Duration);
            parameters["DurationRandomness"].SetFloatValue(ref settings.DurationRandomness);
            parameters["Gravity"].SetVectorValue(ref gravity);
            parameters["EndVelocity"].SetFloatValue(ref settings.EndVelocity);
            parameters["MinColor"].SetVector4Value(ref minColor);
            parameters["MaxColor"].SetVector4Value(ref maxColor);

            parameters["RotateSpeed"].SetVectorValue(ref rotateSpeed);
            parameters["StartSize"].SetVectorValue(ref startSize);
            parameters["EndSize"].SetVectorValue(ref endSize);

            Texture texture = contentManager.Load<Texture2D>(settings.TextureName);
            parameters["ColorTexture"].SetTextureValue(ref texture);

            string techniqueScript = "Color?" + settings.Technique;
            sasEffect.SelectTechniques(techniqueScript);

            return sasEffect;
        }

        public SASParticles Load(string name, ContentManager contentManager)
        {
            if (name == null)
            {
                return null;
            }

            SASParticles particles = null;
            string[] tokens = name.Split(new char[] { '@' });
            if (tokens.Count() == 2)
            {
                ParticleSettingsCollection collection = contentManager.Load<ParticleSettingsCollection>(tokens[0]);
                if (collection != null)
                {
                    string effectName = tokens[0];
                    string settingsName = tokens[1];

                    EffectsTable effects = null;
                    if (!collections.TryGetValue(collection, out effects))
                    {
                        effects = new EffectsTable();
                        collections.Add(collection, effects);
                    }

                    SASEffect effect = null;
                    ParticleSettings settings = null;
                    if (collection.ParticleSettings.TryGetValue(settingsName, out settings))
                    {
                        if (!effects.TryGetValue(name, out effect))
                        {
                            effect = Build(settings, contentManager);
                            effects.Add(name, effect);
                        }
                    }

                    if (effect != null)
                    {
                        particles = new SASParticles(effect, settings);
                    }
                }
            }

            return particles;
        }
        #endregion
    }
}
